//
// File:        rm_filescan.cc
// Description: RM_FileScan class implementation
// Authors:     Haris Wang (dynmiw@gmail.com)
//
// 
#include <cstdio>
#include <unistd.h>
#include <assert.h>
#include <iostream>
#include "rm.h"
#include "rm_rid.h"
#include "rm_internal.h"

RM_FileScan::RM_FileScan(): bOpen(false)
{
    pred = NULL;
    prmh = NULL;
    current = RID(1,-1);
}

RC RM_FileScan::OpenScan  (const RM_FileHandle &fileHandle,
                AttrType   attrType,
                int        attrLength,
                int        attrOffset,
                CompOp     compOp,
                void       *value,
                ClientHint pinHint = NO_HINT)
{
    if(bOpen)
        return (START_RM_ERR - 4);

    prmh = const_cast<RM_FileHandle*>(&fileHandle);
    if( (prmh==NULL) || (prmh->IsValid()!=0) )
        return (START_RM_ERR - 5);
    
    if(value != NULL)
    {

    }

    bOpen = true;
    pred = new Predicate(attrType,       
                       attrLength,
                       attrOffset,
                       compOp,
                       value,
                       pinHint);
    
    return 0;
}

RC RM_FileScan::CloseScan()
{
    if(!bOpen)
        return (START_RM_ERR - 6);
    assert(prmh!=NULL && pred!=NULL);

    bOpen = false;
    if(pred!=NULL)
        delete pred;
    current = RID(1,-1);

    return 0;
}

RC RM_FileScan::GotoPage(PageNum p)
{
    if(!bOpen)
        return (START_RM_ERR - 6);
    assert(prmh!=NULL && pred!=NULL);

    RM_Record rec;
    SlotNum s;
    RID rid;
    GetNextRec(rec);
    rec.GetRid(rid);
    rid.GetSlotNum(s);
    current = RID(p, s-1);

    return 0;
}

RC RM_FileScan::GetNextRec(RM_Record &rec)
{
    if(!bOpen)
        return (START_RM_ERR - 6);
    assert(prmh!=NULL && pred!=NULL);

    PF_PageHandle ph;
    RM_PageHdr pHdr(prmh->GetNumSlots());
    RC rc;
    int s,p,i;
    current.GetPageNum(p);
    for(int j=p; j<(prmh->GetNumPages()); j++)
    {
        if((rc = prmh->pfHandle->GetThisPage(j, ph))
            || (rc = prmh->pfHandle->UnpinPage(j)))
            return rc;

        char* buf;
        rc = ph.GetData(buf);
        pHdr.from_buf(buf);
        if(rc)
            return rc;

        bitmap b(prmh->GetNumSlots(), pHdr.freeSlotMap);
        current.GetPageNum(p);
        current.GetSlotNum(s);
        if(p==j)
            i = s+1;
        else
            i = 0;    

        char *pData;
        while(i < (prmh->GetNumSlots()))
        {
            if(b.test(i))
            {
                i++;
                continue;   // free record - means this is useless to us
            }

            current = RID(j,i);
            prmh->GetRec(current, rec);
            pData = NULL;
            rec.GetData(pData);
            if(pred->eval(pData, pred->initOp()))
                return 0;

            i++;
        }
    }

    return (START_RM_ERR - 8);
}
